package color;

import geom.Geom;
import geom.PolarVector;
import geom.Vector;
import proxml.XMLElement;

public class Hsv{ 
	
	public static float MAX_HUE = (float)Math.PI;
	public static float MIN_HUE = (float)-Math.PI;
	public static float HUE_RANGE = 2 * (float)Math.PI;
	public static float MAX_SATVAL = 1;
	
	public float h, s, v;
	public Hsv(Hsv hsv) { 
		this(hsv.h, hsv.s, hsv.v); 
	}
	public Hsv (float h, float s, float v){ 
		this.h = h; this.s = s;this.v = v; 
	}
	public Hsv (Vector v){ 
		this(v.x, v.y, v.z);
	}
	public String toString(){ 
		return "HSV:{"+h+", "+s+", "+v+"}"; 
	}
	@Override
	public int hashCode() {
		final int PRIME = 31;
		int result = 1;
		result = PRIME * result + Float.floatToIntBits(h);
		result = PRIME * result + Float.floatToIntBits(s);
		result = PRIME * result + Float.floatToIntBits(v);
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Hsv other = (Hsv) obj;
		if (Float.floatToIntBits(h) != Float.floatToIntBits(other.h))
			return false;
		if (Float.floatToIntBits(s) != Float.floatToIntBits(other.s))
			return false;
		if (Float.floatToIntBits(v) != Float.floatToIntBits(other.v))
			return false;
		return true;
	}
	
	public float distanceTo(Hsv hsv){
		return sphericalDistance(this, hsv);
	}

	
	public static float sphericalDistance(Hsv a, Hsv b){
		
		return getSphericalVector(a).getDistance(getSphericalVector(b));
	}
	
	public static Vector getSphericalVector(Hsv a){

		float v = a.v * 2f - 1f;
		float az = a.h;
		float el = Geom.angle(a.s, v);
		float d = (float) Math.sqrt(a.s * a.s + v * v);
		Vector vec = new PolarVector(az, el, d).getCartesian().div(2f);
		return vec;
	}
	
	public Vector directionVector(Hsv to){
		float h = this.h - to.h;
		float s = this.s - to.s;
		float v = this.v - to.v;
		float abs = (float)Math.sqrt(h*h + s*s + v*v);
		return new Vector(h / abs, s / abs, v / abs);
	}
	
	public Vector getVector(){
		return new Vector(h, s, v);
	}
	
	public float getVectorPos(Vector v){
		return (h * v.x + s * v.y + this.v * v.z) / v.absLength();
	}
	
	public XMLElement toXML(){
		XMLElement elem = new XMLElement("hsv");
		elem.addAttribute("h", h);
		elem.addAttribute("s", s);
		elem.addAttribute("v", v);
		return elem;
	}
	
	public Hsv getOppositeBrightness(){
		return new Hsv(h, s, (v + MAX_SATVAL / 2f) % MAX_SATVAL);
	}
	
	public Hsv getComplementary(){
		return new Hsv((h + HUE_RANGE / 2f) % HUE_RANGE, s, v);
	}
	
}